import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_app_demo/podo/forecast_list_model.dart';
import 'package:flutter_app_demo/ui_demo/ui_weather_forecast/generic/circle_position.dart';

class SlidingForecastList extends StatelessWidget {
    
    final ListViewModel listViewModel;
    
    final SlidingListController controller; //暴露给外界，让外界控制list动画什么时候打开，什么时候关闭。
    
    const SlidingForecastList({Key key, this.listViewModel, this.controller }) : super(key: key);
    
    Widget _buildItem(BuildContext context, ListItem viewModel, double currentAngle, double opacity) {
        final size = MediaQuery // 获取屏幕高度
            .of(context)
            .size;
        final dy = size.height / 2 - 30.0;
        
        return Opacity(
            opacity: opacity,
            child: Transform(
                transform: Matrix4.translationValues(0.0, dy, 0),
                child: CirclePosition(
                    
                    angle: currentAngle,
                    radius: 130.0 + 50.0, //130.0半径，50第三个圈的位置
                    
                    child: ForecastItem(
                        
                        listItem: viewModel,
                    
                    ),
                ),
            ),
        );
    }
    
    List<Widget> _buildList(BuildContext context) {
        ///demo刚开始时写死的固定位置
//        final double start = -pi / 2.5;
//        final double end = pi / 2.5;
//        final double angleStep = (end - start) / (listViewModel.items.length - 1);
//
//        double currentAngle = start;
//
//        return listViewModel.items.map((ListItem viewModel) {
//            final item = _buildItem(context, viewModel, currentAngle);
//            currentAngle += angleStep;
//
//            return item;
//        }
//
//        ).toList();
        
        ///从动画控制器中获取item的角度位置和透明度来与AnimatedBuilder配合实现动画
        int index = 0;
        return listViewModel.items.map((ListItem viewModel) {
            final item = _buildItem(
                context,
                viewModel,
                controller.getItemAngle(index),
                controller.getItemOpacity(index)
            );
            index++;
            
            return item;
        }
        
        ).toList();
    }
    
    @override
    Widget build(BuildContext context) {
        return AnimatedBuilder(
            animation: controller, //ChangeNotifier的每一次变化都会触发builder
            builder: (BuildContext buildContext, Widget child) {
                return Stack(
                    children: _buildList(context),
                );
            },
        );
    }
    
}

class ForecastItem extends StatelessWidget {
    
    final ListItem listItem;
    
    ForecastItem({Key key, this.listItem}) : super(key: key);
    
    @override
    Widget build(BuildContext context) {
        BoxDecoration decoration = listItem.isSelect ?
        
        BoxDecoration(
            shape: BoxShape.circle,
            color: Colors.white,
        )
            :
        BoxDecoration(
            shape: BoxShape.circle,
            color: Colors.transparent,
            border: Border.all(
                color: Colors.white,
                width: 2.0,
            )
        );
        
        return Row(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
                
                Container(
                    width: 60.0,
                    height: 60.0,
                    decoration: decoration,
                    
                    child: Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Icon(
                            listItem.icon,
                            color: listItem.isSelect ? Colors.grey : Colors.white,
                        ),
                    )
                ),
                Padding(
                    padding: const EdgeInsets.only(left: 5.0),
                    child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        mainAxisSize: MainAxisSize.min,
                        children: <Widget>[
                            Text(listItem.title, style: TextStyle(color: Colors.white, fontSize: 18.0),),
                            Text(listItem.subTitle, style: TextStyle(color: Colors.white, fontSize: 20.0),),
                        ],
                    ),
                ),
            ],
        );
    }
}

class SlidingListController extends ChangeNotifier {
    
    List<Animation<double>>_slideAnimations; //每个item的进入的动画时间都不一致，所以需要多个动画
    final firstItemAngle = -pi / 2.5; //第一个item在屏幕上的旋转移动的角度位置
    final lastItemAngle = pi / 2.5; //最后一个item在屏幕上的旋转移动的角度位置
    final startSlideAngle = 3 * pi / 2.5; //在屏幕上的旋转移动的起始角度位置
    
    final AnimationController _slideController;
    final AnimationController _fadeController;
    
    TickerProvider vsync;
    int itemCount;
    
    SlidingListState _state = SlidingListState.closed;
    
    Completer<Null> onOpenedCompleter;
    Completer<Null> onClosedCompleter;
    
    SlidingListController({
        this.itemCount,
        @required this.vsync,
    })
        :
            this._slideController = AnimationController(
                duration: const Duration(milliseconds: 1500),
                vsync: vsync,
            ),
            this._fadeController = AnimationController(
                duration: const Duration(milliseconds: 200),
                vsync: vsync,
            ),
            this._slideAnimations = [] {
        _slideController
            ..addStatusListener((AnimationStatus status) {
                switch (status) {
                    case AnimationStatus.forward : //动画开始时，列表正在滑入
                        _state = SlidingListState.slidingOpen;
                        notifyListeners(); //将动画的状态交给感兴趣的"合作方"
                        break;
                    case AnimationStatus.completed : //动画结束时，列表滑入完成呈打开状态
                        _state = SlidingListState.open;
                        
                        onOpenedCompleter.complete();
                        notifyListeners(); //将动画的状态交给感兴趣的"合作方"
                        break;
                    
                    case AnimationStatus.dismissed : //其他状态不考虑
                    case AnimationStatus.reverse :
                    default:
                        break;
                }
            })
            ..addListener(() {
                notifyListeners(); //将动画的每一帧交给感兴趣的"合作方"
            });
        
        _fadeController
            ..addStatusListener((AnimationStatus status) {
                switch (status) {
                    case AnimationStatus.forward : //动画开始时，列表正在淡出
                        _state = SlidingListState.fadingOutClose;
                        notifyListeners(); //将动画的状态交给感兴趣的"合作方"
                        break;
                    case AnimationStatus.completed : //动画结束时，列表滑入完成呈关闭状态
                        _state = SlidingListState.closed;
                        
                        //此处是一个绝佳的机会重置动画
                        _slideController.value = 0.0;
                        _fadeController.value = 0.0;
                        
                        onClosedCompleter.complete();
                        notifyListeners(); //将动画的状态交给感兴趣的"合作方"
                        break;
                    
                    case AnimationStatus.dismissed : //其他状态不考虑
                    case AnimationStatus.reverse :
                    default:
                        break;
                }
            })
            ..addListener(() {
                notifyListeners(); //将动画的每一帧交给感兴趣的"合作方"
            });
        
        //_slideAnimations =
        
        final itemDelay = 0.1; //整个时长的后延百分比
        final slideDuration = 0.5; //整个时长的百分比
        
        final itemAngleDelta = (lastItemAngle - firstItemAngle) / (itemCount - 1); //每个item的角度差
        for (var i = 0; i < itemCount; i++) {
            final start = itemDelay * i; // 每个item的动画起始时间往后延
            final end = start + slideDuration;
            
            final endItemAngle = firstItemAngle + (itemAngleDelta * i);
            
            _slideAnimations.add( //构造itemCount个动画, 注意此处，将item动画的value变化"映射"为了item的角度变化
                Tween(
                    begin: startSlideAngle, //起始角度位置
                    end: endItemAngle //每个item结束时的角度位置
                ).animate( //animate函数的意义：Tween动画"依赖"CurvedAnimation驱动
                    CurvedAnimation(
                        parent: _slideController,
                        curve: Interval(start, end, curve: Curves.easeInOut)
                    )
                )
            );
        }
    }
    
    Future<Null> open() {
        if (_state == SlidingListState.closed) {
            _slideController.forward();
            
            onOpenedCompleter = Completer();
            return onOpenedCompleter.future;
        }
        return null;
    }
    
    Future<Null> close() {
        if (_state == SlidingListState.open) {
            _fadeController.forward();
            
            onClosedCompleter = Completer();
            return onClosedCompleter.future;
        }
        
        return null;
    }
    
    double getItemAngle(int index) {
        return _slideAnimations[index].value; //注意动画数组的构造过程，实际的目的并不是构造一个"动画"，而是要的是"动画"播放过程中的值的变化
    }
    
    double getItemOpacity(int index) {
        //获取列表每个item的当前动画的透明度
        switch (_state) {
            case SlidingListState.closed:
                return 0.0;
            case SlidingListState.slidingOpen:
            case SlidingListState.open:
                return 1.0;
            case SlidingListState.fadingOutClose:
                return (1.0 - _fadeController.value); //时刻注意，动画的值从0.0增加到1.0
        }
        return 1.0;
    }
    
    @override
    void dispose() {
        _fadeController.dispose();
        _slideController.dispose();
        super.dispose();
    }
    
}

enum SlidingListState {
    closed,
    slidingOpen,
    open,
    fadingOutClose
}